package com.example.demo.jeePay;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.util.StringUtils;

import java.util.regex.Pattern;

/**
 * IP地址工具类
 * 用于获取客户端真实IP地址，支持代理环境下的IP解析
 * 
 * @author MingChang.Wei
 * @since 2025/6/9
 */
public class IpUtil {
    
    /**
     * IPv4地址正则表达式
     */
    private static final Pattern IPV4_PATTERN = Pattern.compile(
            "^(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\." +
            "(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\." +
            "(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\." +
            "(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)$"
    );
    
    /**
     * 常见的代理请求头列表，按优先级排序
     */
    private static final String[] PROXY_HEADERS = {
            "X-Forwarded-For",
            "X-Real-IP", 
            "Proxy-Client-IP",
            "WL-Proxy-Client-IP",
            "HTTP_CLIENT_IP",
            "HTTP_X_FORWARDED_FOR"
    };
    
    /**
     * 默认IP地址（当无法获取到有效IP时返回）
     */
    private static final String DEFAULT_IP = "0.0.0.0";

    /**
     * 获取客户端真实IP地址
     * 支持多种代理环境下的IP解析，包括 Nginx、Apache、CDN 等
     * 
     * @param request HTTP请求对象
     * @return 客户端真实IP地址，获取失败时返回默认IP
     */
    public static String getClientIp(HttpServletRequest request) {
        if (request == null) {
            return DEFAULT_IP;
        }
        
        // 遍历所有可能的代理请求头
        for (String header : PROXY_HEADERS) {
            String ip = parseHeader(request, header);
            if (isValidIp(ip)) {
                return ip;
            }
        }
        
        // 最后尝试从 RemoteAddr 获取
        String remoteAddr = request.getRemoteAddr();
        return isValidIp(remoteAddr) ? remoteAddr : DEFAULT_IP;
    }

    /**
     * 解析HTTP请求头中的IP地址
     * 处理多IP情况（如：X-Forwarded-For: client, proxy1, proxy2）
     * 
     * @param request HTTP请求对象
     * @param header 请求头名称
     * @return 解析出的有效IP地址，若无有效IP则返回null
     */
    private static String parseHeader(HttpServletRequest request, String header) {
        String value = request.getHeader(header);
        if (!StringUtils.hasText(value)) {
            return null;
        }
        
        // 过滤掉常见的无效值
        value = value.toLowerCase();
        if ("unknown".equals(value) || "null".equals(value) || "-".equals(value)) {
            return null;
        }
        
        // 处理多个IP地址（取第一个有效的IP，优先公网IP）
        String[] ips = value.split(",");
        String firstValidIp = null;
        
        for (String ip : ips) {
            String trimmedIp = ip.trim();
            if (isValidIp(trimmedIp)) {
                if (firstValidIp == null) {
                    firstValidIp = trimmedIp; // 记录第一个有效IP
                }
                if (isValidPublicIp(trimmedIp)) {
                    return trimmedIp; // 优先返回公网IP
                }
            }
        }
        
        return firstValidIp; // 如果没有公网IP，返回第一个有效IP
    }

    /**
     * 验证IP地址格式是否有效
     * @param ip 待验证的IP地址字符串
     * @return 如果是有效的IPv4地址格式则返回true，否则返回false
     */
    private static boolean isValidIp(String ip) {
        return StringUtils.hasText(ip) && 
               !ip.toLowerCase().contains("unknown") &&
               IPV4_PATTERN.matcher(ip).matches();
    }
    
    /**
     * 验证是否为有效的公网IP地址
     * 过滤掉内网IP和其他无效IP
     * 
     * @param ip 待验证的IP地址字符串
     * @return 如果是有效的公网IPv4地址则返回true，否则返回false
     */
    private static boolean isValidPublicIp(String ip) {
        if (!isValidIp(ip)) {
            return false;
        }
        
        // 过滤内网IP段
        if (isPrivateIp(ip)) {
            return false;
        }
        
        // 过滤其他特殊IP
        return !ip.startsWith("127.") &&    // 回环地址
               !ip.startsWith("0.") &&      // 无效地址
               !ip.equals("255.255.255.255"); // 广播地址
    }
    
    /**
     * 判断是否为内网IP地址
     * 
     * @param ip IP地址
     * @return 如果是内网IP则返回true
     */
    private static boolean isPrivateIp(String ip) {
        return ip.startsWith("10.") ||                                    // 10.0.0.0/8
               (ip.startsWith("172.") && isInRange(ip, 16, 31)) ||       // 172.16.0.0/12
               ip.startsWith("192.168.");                                 // 192.168.0.0/16
    }
    
    /**
     * 检查172.x.x.x是否在指定范围内
     * 
     * @param ip IP地址
     * @param start 起始值
     * @param end 结束值
     * @return 是否在范围内
     */
    private static boolean isInRange(String ip, int start, int end) {
        String[] parts = ip.split("\\.");
        if (parts.length != 4) {
            return false;
        }
        try {
            int secondOctet = Integer.parseInt(parts[1]);
            return secondOctet >= start && secondOctet <= end;
        } catch (NumberFormatException e) {
            return false;
        }
    }
    
    /**
     * 获取客户端IP地址（包含内网IP）
     * 当无法获取公网IP时，返回内网IP
     * 
     * @param request HTTP请求对象
     * @return 客户端IP地址
     */
    public static String getClientIpIncludePrivate(HttpServletRequest request) {
        if (request == null) {
            return DEFAULT_IP;
        }
        
        // 遍历所有可能的代理请求头
        for (String header : PROXY_HEADERS) {
            String value = request.getHeader(header);
            if (StringUtils.hasText(value) && !"unknown".equalsIgnoreCase(value)) {
                String[] ips = value.split(",");
                for (String ip : ips) {
                    String trimmedIp = ip.trim();
                    if (isValidIp(trimmedIp)) {
                        return trimmedIp;
                    }
                }
            }
        }
        
        // 最后尝试从 RemoteAddr 获取
        String remoteAddr = request.getRemoteAddr();
        return isValidIp(remoteAddr) ? remoteAddr : DEFAULT_IP;
    }
    
    /**
     * 判断IP地址是否为公网IP
     * 
     * @param ip IP地址
     * @return 如果是公网IP则返回true
     */
    public static boolean isPublicIp(String ip) {
        return isValidPublicIp(ip);
    }
    
    /**
     * 获取IP地址的地理位置类型
     * 
     * @param ip IP地址
     * @return IP地址类型描述
     */
    public static String getIpType(String ip) {
        if (!isValidIp(ip)) {
            return "无效IP";
        }
        
        if (ip.startsWith("127.")) {
            return "本地回环";
        }
        
        if (isPrivateIp(ip)) {
            return "内网IP";
        }
        
        if (ip.startsWith("169.254.")) {
            return "链路本地地址";
        }
        
        return "公网IP";
    }
}
